package com.hup.utils.algorithm.image;

import lombok.extern.log4j.Log4j2;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author hugan
 * @date 2020/4/30
 */
@Log4j2
class ThreadPoolUtil {

    /**
     * 固定线程的执行器
     * <pre>
     * 配置
     *  常驻线程:0
     *  最大线程:threadCount
     *  最大任务数:threadCount+0等待队列
     *  回收间隔:10秒
     * </pre>
     *
     * @param threadNamePrefix 线程名前缀,一般以'-'结尾
     * @param executorDesc 执行器描述,如[窗口标题];用于 {@link RejectedExecutionException} 的消息描述
     */
    public static ThreadPoolExecutor fixedThreadExecutor(String threadNamePrefix, int threadCount, String executorDesc) {
        return new ThreadPoolExecutor(
                0,
                threadCount,
                10, TimeUnit.SECONDS,
                new SynchronousQueue<>(),
                //实现修改线程名前缀
                new PrefixAbleThreadFactory(threadNamePrefix),
                //达到最大任务时抛出异常
                new SimpleRejectedHandler(executorDesc)
        );
    }

    /**
     * java.util.concurrent.Executors.DefaultThreadFactory
     */
    public static class PrefixAbleThreadFactory implements ThreadFactory {
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        PrefixAbleThreadFactory(String threadNamePrefix) {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                    Thread.currentThread().getThreadGroup();
            namePrefix = threadNamePrefix;
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                    namePrefix + threadNumber.getAndIncrement(),
                    0);
            if (t.isDaemon())
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

    public static class SimpleRejectedHandler implements RejectedExecutionHandler {

        private final String executorDesc;

        public SimpleRejectedHandler(String executorDesc) {
            this.executorDesc = executorDesc;
        }

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            if (executor.isShutdown()) throw new RejectedExecutionException("[" + executorDesc + "]执行器已被停止");
            throw new RejectedExecutionException("[" + executorDesc + "]异步任务数量已达到最大值");
        }
    }

}
